package com.jzo2o.customer.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
import com.jzo2o.common.expcetions.ForbiddenOperationException;
import com.jzo2o.common.model.CurrentUserInfo;
import com.jzo2o.common.model.PageResult;
import com.jzo2o.common.utils.CollUtils;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.customer.enums.AuditStatusEnum;
import com.jzo2o.customer.enums.CertificationStatusEnum;
import com.jzo2o.customer.mapper.ServeProviderMapper;
import com.jzo2o.customer.mapper.WorkerCertificationAuditMapper;
import com.jzo2o.customer.mapper.WorkerCertificationMapper;
import com.jzo2o.customer.model.domain.ServeProvider;
import com.jzo2o.customer.model.domain.WorkerCertification;
import com.jzo2o.customer.model.domain.WorkerCertificationAudit;
import com.jzo2o.customer.model.dto.request.WorkerCertificationAuditPageQueryReqDTO;
import com.jzo2o.customer.model.dto.response.RejectReasonResDTO;
import com.jzo2o.customer.model.dto.response.WorkerCertificationAuditResDTO;
import com.jzo2o.customer.service.IWorkerCertificationAuditService;
import com.jzo2o.mvc.utils.UserContext;
import com.jzo2o.mysql.utils.PageUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 服务人员认证审核服务实现类
 */
@Service
public class WorkerCertificationAuditServiceImpl extends ServiceImpl<WorkerCertificationAuditMapper, WorkerCertificationAudit> implements IWorkerCertificationAuditService {
    @Resource
    private WorkerCertificationMapper workerCertificationMapper;
    @Resource
    private ServeProviderMapper serveProviderMapper;

    /**
     * 服务人员 - 查询最新驳回原因
     *
     * @return 最新驳回原因
     */
    @Override
    @SuppressWarnings("unchecked")
    public RejectReasonResDTO getLatestRejectReason() {
        //1、获取当前登录用户的id
        Long userId = UserContext.currentUserId();
        //2、判断当前登录用户是否存在
        if (ObjectUtils.isEmpty(userId)) {
            throw new ForbiddenOperationException("用户不存在无法查询");
        }
        //3、查询当前登录用户最新的认证审核记录
        List<WorkerCertificationAudit> certificationAudits = lambdaQuery()
                .eq(WorkerCertificationAudit::getCertificationStatus, CertificationStatusEnum.FAIL.getStatus()) //认证失败
                .eq(WorkerCertificationAudit::getServeProviderId, userId)
                .orderByDesc(WorkerCertificationAudit::getCreateTime) // 最新创建时间
                .list();
        //4、返回最新驳回原因
        return CollUtils.isEmpty(certificationAudits)
                ? new RejectReasonResDTO()
                : new RejectReasonResDTO(certificationAudits.get(0).getRejectReason());
    }


    /**
     * 运营端 - 审核服务人员认证-分页查询
     *
     * @param pageQueryReqDTO 查询参数
     * @return 服务人员认证审核列表
     */
    @Override
    public PageResult<WorkerCertificationAuditResDTO> queryPage(WorkerCertificationAuditPageQueryReqDTO pageQueryReqDTO) {
        // 1、 将前端传递的分页参数（DTO）解析为MP的Page对象（含页码、页大小、排序规则）
        Page<WorkerCertificationAudit> pageQuery = PageUtils.parsePageQuery(pageQueryReqDTO, WorkerCertificationAudit.class);

        // 2、 构建查询条件 - 通过 Wrappers 工具类静态方法创建，一步链式完成（创建 + 加条件）
        String name = pageQueryReqDTO.getName(); // 姓名
        String idCardNo = pageQueryReqDTO.getIdCardNo(); // 身份证号
        Integer auditStatus = pageQueryReqDTO.getAuditStatus(); // 审核状态
        Integer certificationStatus = pageQueryReqDTO.getCertificationStatus(); // 认证状态
        LambdaQueryWrapper<WorkerCertificationAudit> queryWrapper = Wrappers.<WorkerCertificationAudit>lambdaQuery()
                .like(ObjectUtils.isNotEmpty(name), WorkerCertificationAudit::getName, name)
                .like(ObjectUtils.isNotEmpty(idCardNo), WorkerCertificationAudit::getIdCardNo, idCardNo)
                .eq(ObjectUtils.isNotEmpty(auditStatus), WorkerCertificationAudit::getAuditStatus, auditStatus)
                .eq(ObjectUtils.isNotEmpty(certificationStatus), WorkerCertificationAudit::getCertificationStatus, certificationStatus);

        // 3、 调用MP的默认分页查询方法：根据page（分页参数）和queryWrapper（筛选条件）执行SQL
        // 执行后，page对象会自动填充总条数、总页数、当前页数据等信息
        return PageUtils.toPage(
                baseMapper.selectPage(pageQuery, queryWrapper),
                WorkerCertificationAuditResDTO.class);
    }

    /**
     * 运营端 - 审核服务人员认证信息
     *
     * @param id                  认证记录id
     * @param certificationStatus 认证状态
     * @param rejectReason        拒绝原因
     */
    @Override
    public void audit(Long id, Integer certificationStatus, String rejectReason) {
        //1、根据id查询认证记录
        WorkerCertificationAudit workerCertificationAudit = baseMapper.selectById(id);
        if (ObjectUtils.isEmpty(workerCertificationAudit)) {
            throw new ForbiddenOperationException("认证记录不存在无法审核");
        }
        //2、通过ThreadLocal获取当前登录的用户信息
        CurrentUserInfo currentUserInfo = UserContext.currentUser();
        if (ObjectUtils.isEmpty(currentUserInfo) || ObjectUtils.isEmpty(currentUserInfo.getId())) {
            throw new ForbiddenOperationException("无法获取当前用户信息");
        }

        //3、准备审核人相关-公共部分的数据
        LocalDateTime now = LocalDateTime.now(); // 当前时间
        workerCertificationAudit.setCertificationStatus(certificationStatus); // 认证状态
        //构建更新条件 - 更新 worker_certification_audit表
        LambdaUpdateChainWrapper<WorkerCertificationAudit> updateChainWrapper = lambdaUpdate()
                .eq(WorkerCertificationAudit::getId, id) // 认证记录id
                .set(WorkerCertificationAudit::getAuditStatus, AuditStatusEnum.AUDITED.getStatus()) // 审核状态设为已审核
                .set(WorkerCertificationAudit::getAuditTime, now) // 审核时间设为当前时间
                .set(WorkerCertificationAudit::getAuditorId, currentUserInfo.getId()) // 审核人设为当前登录用户
                .set(WorkerCertificationAudit::getAuditorName, currentUserInfo.getName()) // 审核人名称设为当前登录用户名称
                .set(WorkerCertificationAudit::getCertificationStatus, certificationStatus); // 认证状态设为-前端给的认证状态

        //4、根据认证状态进行不同处理
        String name = ""; //用来保存姓名
        //获取服务人员id
        Long serveProviderId = workerCertificationAudit.getServeProviderId();
        //4.1、认证失败
        if (certificationStatus == CertificationStatusEnum.FAIL.getStatus()) {
            //更新拒绝原因
            updateChainWrapper
                    .set(WorkerCertificationAudit::getRejectReason, rejectReason) // 拒绝原因设为-前端给的拒绝原因
                    .update();
            //服务人员认证失败 - 对 worker_certification 表进行认证失败更新
            workerCertificationMapper.updateById(WorkerCertification.builder()
                    .id(serveProviderId) //服务人员id
                    .certificationStatus(certificationStatus) //认证状态设为-认证失败
                    .certificationTime(now) //认证时间设为当前时间
                    .build());
        } else {
            //4.2、认证成功
            updateChainWrapper
                    .update();

            // 服务人员认证成功 - 对 worker_certification 表进行完整数据填充
            workerCertificationMapper.updateById(WorkerCertification.builder()
                    .id(serveProviderId) //服务人员id
                    .name(workerCertificationAudit.getName()) //姓名设为-认证记录中的姓名
                    .idCardNo(workerCertificationAudit.getIdCardNo()) //身份证号设为-认证记录中的身份证号
                    .frontImg(workerCertificationAudit.getFrontImg()) //身份证正面设为-认证记录中的身份证正面
                    .backImg(workerCertificationAudit.getBackImg()) //身份证反面设为-认证记录中的身份证反面
                    .certificationMaterial(workerCertificationAudit.getCertificationMaterial()) //认证资料设为-认证记录中的认证资料
                    .certificationStatus(certificationStatus) //认证状态设为-认证成功
                    .certificationTime(now).build()); //认证时间设为当前时间
            name = workerCertificationAudit.getName(); // 姓名
        }

        // 更新总表中的服务人员姓名
        ChainWrappers.lambdaUpdateChain(serveProviderMapper)
                .eq(ServeProvider::getId, serveProviderId)
                .set(ServeProvider::getName, name)
                .update();
    }
}

